package com.espirit.eap.util;

import java.io.File;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.annotation.Resource;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mozilla.javascript.CompilerEnvirons;
import org.mozilla.javascript.Parser;
import org.mozilla.javascript.ast.AstNode;
import org.mozilla.javascript.ast.AstRoot;
import org.mozilla.javascript.ast.FunctionNode;
import org.mozilla.javascript.ast.Name;
import org.mozilla.javascript.ast.NodeVisitor;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Service;

import com.googlecode.cswish.Config;

@Service
public class JavaScriptManager {
	private static final Log logger = LogFactory
			.getLog(JavaScriptManager.class);

	@Resource
	private Config config;

	// jsName -- parameters
	private Map<String, String> jsInfos;

	public JavaScriptManager() {
	}

	public Map<String, String> getJsInfos() {
		if (jsInfos == null) {
			jsInfos = new LinkedHashMap<String, String>();
			init();
		}
		return jsInfos;
	}

	private void init() {
		String rootPath = config.getRealWebRootPath();

		String[] taglibFiles = new String[] { "/static/espirit/scripts/jtaglib.js" };
		boolean hasScriptFile = new File(rootPath + taglibFiles[0]).exists();
		if (hasScriptFile) {
			for (String taglibFile : taglibFiles) {
				try {
					String content = FileUtils.readFileToString(new File(
							rootPath + taglibFile), "UTF-8");
					parse(content);
				} catch (Exception ex) {
					logger.error("Failed to read tag file:" + taglibFile, ex);
				}
			}
		} else {
			StringBuilder scriptFile = new StringBuilder();
			for (String file : taglibFiles) {
				if (scriptFile.length() > 0) {
					scriptFile.append(',');
				}
				scriptFile.append(file);
			}
			ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
			String packageSearchPath = "classpath*:" + scriptFile;

			try {
				org.springframework.core.io.Resource[] resources = resourcePatternResolver
						.getResources(packageSearchPath);
				for (org.springframework.core.io.Resource resource : resources) {
					String content = IOUtils
							.toString(resource.getInputStream());
					parse(content);
				}
			} catch (Exception ex) {
				logger.error("Failed to read tag file", ex);
			}
		}
	}

	/*
	protected void initJsFile(String content) {
		String nameExpression = "(\\w+)";
		String paramExpression = "([^()]*)";
		String expression = "function\\s*" + nameExpression + "\\s*\\(\\s*"
				+ paramExpression + "\\s*\\)";

		Pattern pattern = Pattern.compile(expression);
		Matcher matcher = pattern.matcher(content);

		while (matcher.find()) {
			String funcName = matcher.group(1);
			String funcParam = matcher.group(2);

			jsInfos.put(funcName, funcParam);
		}
	}*/

	private void parse(String content) {
		class Printer implements NodeVisitor {
			@Override
			public boolean visit(AstNode node) {
				if (node instanceof FunctionNode) {		// TODO: parse ExpressionStatement
					FunctionNode fNode = (FunctionNode)node;
					String functionName = fNode.getName();
					if (functionName.length() > 0 && functionName.charAt(0) != '_') {
						int count = fNode.getParamCount();
						String parameters;
						if (count > 0) {
							StringBuilder sb = new StringBuilder();
							boolean firstNode = true;
							for (AstNode param : fNode.getParams()) {
								if (firstNode) {
									firstNode = false;
								} else {
									sb.append(',');
								}
								Name name = (Name)param;
								String str = name.getString();
								sb.append(str);
							}
							parameters = sb.toString();
						} else {
							parameters = "";
						}
						
						jsInfos.put(functionName, parameters);
					}
					return false;
				} else {
					return true;
				}
			}
		}
		
		try {
			CompilerEnvirons env = new CompilerEnvirons();
			AstRoot node = new Parser(env).parse(content, "", 1);
			node.visitAll(new Printer());
		} catch (Exception ex) {
			logger.error("parse resource", ex);
		}
	}
	
	public static void main(String[] args) throws IOException {
		String file = "D:\\workspace\\espirit\\espirit-core\\src\\main\\resources\\static\\espirit\\scripts\\jtaglib.js";
		String content = FileUtils.readFileToString(new File(file));
		JavaScriptManager javaScriptManager = new JavaScriptManager();
		javaScriptManager.jsInfos = new LinkedHashMap<String, String>();
		javaScriptManager.parse(content);
		
		for (Entry<String, String> entry : javaScriptManager.jsInfos.entrySet()) {
			System.out.println(entry.getValue());
		}
	}
}